/**
 * Copyright 2013 yangming.liu<liuyangming@gmail.com>.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, see <http://www.gnu.org/licenses/>.
 */
package org.bytesoft.openjta.recovery;

import java.rmi.RemoteException;
import java.util.Iterator;

import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.bytesoft.openjta.TransactionStatus;
import org.bytesoft.openjta.archive.TerminatorArchive;
import org.bytesoft.openjta.archive.XAResourceArchive;
import org.bytesoft.openjta.internal.TransactionVote;
import org.bytesoft.openjta.internal.XAResourceWrapper;
import org.bytesoft.openjta.resource.Terminator;
import org.bytesoft.openjta.xa.BranchXidImpl;
import org.bytesoft.openjta.xa.XidImpl;

public class LAORecoveredTransactionImpl extends RecoveredTransaction {
	private static final long serialVersionUID = 1L;

	protected void regulatePreparingTransaction(boolean failureExists) throws IllegalStateException {
		this.transactionStatus.transferToRollingback();
		this.recoveryRollbackRequired = true;
	}

	protected void regulatePreparedTransaction() throws IllegalStateException {
		Iterator<TerminatorArchive> terminatorItr = this.terminatorArchives.iterator();
		while (terminatorItr.hasNext()) {
			TerminatorArchive archive = terminatorItr.next();
			boolean lastResource = archive.isLastResource();
			if (lastResource) {
				boolean commitStarted = archive.isCommitStarted();
				boolean commitSuccess = archive.isCommitSuccess();
				boolean commitFailure = archive.isCommitFailure();

				if (commitStarted) {
					if (commitSuccess) {
						this.transactionStatus.transferToCommitting();
						this.recoveryRollbackRequired = false;
					} else if (commitFailure) {
						// this.transactionStatus.transferToRollingback();
						// this.recoveryRollbackRequired = true;
						this.transactionStatus.transferToCommitting();
						this.recoveryRollbackRequired = false;
					} else {
						Terminator terminator = archive.getTerminator();
						try {
							int remoteStatus = terminator.getStatus();
							TransactionStatus txStatus = new TransactionStatus();
							txStatus.setCurrentStatus(remoteStatus);
							txStatus.setLastestStatus(remoteStatus);
							if (txStatus.isPrepared()) {
								this.transactionStatus.transferToCommitting();
								this.recoveryRollbackRequired = false;
							} else if (txStatus.isCommitting()) {
								this.transactionStatus.transferToCommitting();
								this.recoveryRollbackRequired = false;
							} else if (txStatus.isCommitFail()) {
								// this.transactionStatus.transferToRollingback();
								// this.recoveryRollbackRequired = true;
								this.transactionStatus.transferToCommitting();
								this.recoveryRollbackRequired = false;
							} else if (txStatus.isCommitted()) {
								this.transactionStatus.transferToCommitting();
								this.recoveryRollbackRequired = false;
							} else {
								this.transactionStatus.transferToRollingback();
								this.recoveryRollbackRequired = true;
							}
						} catch (RemoteException ex) {
							throw new IllegalStateException(ex);
						} catch (RuntimeException ex) {
							throw new IllegalStateException(ex);
						}
					}
				} else {
					this.recoveryRollbackRequired = false;
					this.transactionStatus.transferToRollingback();
					this.transactionLogger.enterRollbackPhase(this);
				}
			} else {
				continue;
			}
		}
	}

	protected void regulateCommittingTransaction(boolean failureExists) throws IllegalStateException {

		// boolean allResourceCommitted = false;
		Iterator<XAResourceArchive> xaResourceItr = this.xaResourceArchives.iterator();
		while (xaResourceItr.hasNext()) {
			XAResourceArchive archive = xaResourceItr.next();
			boolean commitStarted = archive.isCommitStarted();
			boolean commitSuccess = archive.isCommitSuccess();
			boolean commitFailure = archive.isCommitFailure();
			if (archive.getResourceVote() == TransactionVote.XA_RDONLY) {
				// ignore
			} else if (commitStarted) {
				if (commitSuccess) {
					// ignore
				} else if (commitFailure) {
					// TODO
				} else {
					XidImpl branchXid = archive.getBranchXid();
					XAResourceWrapper xares = archive.getXAResource();
					boolean recovered = false;
					try {
						Xid[] array = xares.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
						for (int i = 0; i < array.length; i++) {
							Xid xid = array[i];
							if (xid.getFormatId() == XidImpl.xidFormatId) {
								byte[] globalTransactionId = xid.getGlobalTransactionId();
								byte[] branchQualifier = xid.getBranchQualifier();
								XidImpl recoveredXid = new BranchXidImpl(globalTransactionId, branchQualifier);
								if (recoveredXid.equals(branchXid)) {
									recovered = true;
									break;
								}
							} else {
								continue;
							}
						}
					} catch (XAException xae) {
						// allResourceCommitted = false;

						switch (xae.errorCode) {
						case XAException.XAER_RMERR:
						case XAException.XAER_RMFAIL:
						case XAException.XAER_INVAL:
						case XAException.XAER_PROTO:
							throw new IllegalStateException(xae);
						}
					} catch (RuntimeException rex) {
						throw new IllegalStateException();
					}

					if (recovered) {
						// allResourceCommitted = false;
					} else {
						archive.setCommitResult(true);
					}

				}
			} else {
				// allResourceCommitted = false;
			}
		}

	}

	protected void regulateRollingbackTransaction(boolean failureExists) throws IllegalStateException {
	}

}
